game.tsx ➔ getData   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
1
import ReactFitText from "@kennethormandy/react-fittext"
2
import { useState, useEffect, Fragment } from "react"
3
import { useSiteMetaData } from "../hooks/use-site-metadata"
4
import iconBench from "../images/i_bench_2.png"
5
import iconCardRed from "../images/i_card_red.png"
6
import iconCardYellow from "../images/i_card_yellow.png"
7
import iconCardYellowRed from "../images/i_card_yellow_red.png"
8
import iconGoal from "../images/i_goal.png"
9
import iconStart from "../images/i_start.png"
10
import iconSubIn from "../images/i_sub_in.png"
11
import iconSubOut from "../images/i_sub_out.png"
12
import { MatchDetails, MatchDetailsEventItem, MatchDetailsLineupItem, MatchDetailsSubstituteItem } from "../Types/Match"
13
import { GamePageProps } from "../Types/PageProps"
14
import { DateTime, Settings } from "luxon"
15
import React from "react"
16
import Layout from "../layouts"
17
import { Spinner } from "../components/Spinner"
18
import { Seo } from "../components/Seo"
19
import "./game.scss"
20
import { mapPsdStatus, request } from "../scripts/helper"
21
import LazyLoad from "react-lazy-load"
22
import Icon from "../components/Icon"
23
import { MiniRanking } from "../components/MiniRanking"
24
25
const officialCompetitionTypes = [
26
  'OFFICIAL',
27
  'COMPETITION',
28
  'Competitie'
29
]
30
31
const GamePage = ({ matchId }: GamePageProps) => {
32
  const { kcvvPsdApi } = useSiteMetaData()
33
  const [data, setData] = useState<MatchDetails>()
34
35
  useEffect(() => {
36
    async function getData() {
37
      const response = await request.get(`${kcvvPsdApi}/match/${matchId}`)
38
      setData(response.data)
39
    }
40
    getData()
41
  }, [kcvvPsdApi, matchId])
42
43
  Settings.defaultZone = `Europe/Brussels`
44
  Settings.defaultLocale = `nl-be`
45
46
  if (matchId === null) {
47
    return (
48
      <Layout>
49
        <main className="page__wrapper">Geen match beschikbaar...</main>
50
      </Layout>
51
    )
52
  }
53
54
  if (data) {
55
    const { general, substitutes, lineup, events = [] } = data || {}
56
    const { home: homeLineup = [], away: awayLineup = [] } = lineup || {}
57
    const { home: homeSubs = [], away: awaySubs = [] } = substitutes || {}
58
59
    const matchTime = DateTime.fromFormat(general.date, `yyyy-MM-dd HH:mm`)
60
    const homeTeamId = general.homeClub?.id
61
62
    const ogImage = {
63
      src: general?.homeClub?.logo,
64
      width: 180,
65
      height: 180,
66
    }
67
68
    return (
69
      <Layout>
70
        <Seo
71
          title={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
72
            general.awayClub?.abbreviation || general?.awayClub?.name
73
          }`}
74
          description={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
75
            general.awayClub?.abbreviation || general?.awayClub?.name
76
          }`}
77
          path={`/game/${general?.id}`}
78
          image={ogImage}
79
        />
80
        <header className="game__header__wrapper full-width">
81
          <div className="game__header__inner">
82
            <div className="game__teams">
83
              <div className={`game__teams-inner`}>
84
                <LazyLoad>
85
                  <img src={general.homeClub?.logo} alt={general.homeClub?.name} title={general.homeClub?.name} />
86
                </LazyLoad>
87
              </div>
88
              {renderScore(general.goalsHomeTeam, general.goalsAwayTeam)}
89
              <div className={`game__teams-inner`}>
90
                <LazyLoad>
91
                  <img src={general.awayClub?.logo} alt={general.awayClub?.name} title={general.awayClub?.name} />
92
                </LazyLoad>
93
              </div>
94
            </div>
95
            <h1>
96
              <ReactFitText compressor={2.5}>{`${general.homeClub?.abbreviation || general.homeClub?.name} - ${
97
                general.awayClub?.abbreviation || general.awayClub?.name
98
              }`}</ReactFitText>
99
            </h1>
100
            <h4>{general.competitionType}</h4>
101
            <time dateTime={matchTime.toFormat(`EEEE dd LLLL - H:mm`)}>
102
              {matchTime.toFormat(`EEEE dd LLLL - H:mm`)}
103
            </time>
104
            <br />
105
106
            {general.status !== 0 && (
107
              <span className={`game__status game__status--${general.status}`}>{mapPsdStatus(general.status)}</span>
108
            )}
109
110
            <br />
111
          </div>
112
        </header>
113
114
        <main className="page__wrapper">
115
          {(homeLineup.length !== 0 || awayLineup.length !== 0) && (
116
            <div className={`lineup__wrapper`}>
117
              <div className={`lineup__wrapper--home`}>
118
                <h3>{general.homeClub?.abbreviation || general.homeClub?.name}</h3>
119
                {homeLineup && renderLineup(homeLineup, homeSubs)}
120
              </div>
121
              <div className={`lineup__wrapper--away`}>
122
                <h3>{general.awayClub?.abbreviation || general.awayClub?.name}</h3>
123
                {awayLineup && renderLineup(awayLineup, awaySubs)}
124
              </div>
125
            </div>
126
          )}
127
        </main>
128
129
        <section className="page__wrapper">
130
          {events.length !== 0 && (
131
            <div className={`event__wrapper`}>
132
              <h3>Gebeurtenissen</h3>
133
              {events && renderEvents(events, homeTeamId)}
134
            </div>
135
          )}
136
137
          {officialCompetitionTypes.includes(general.competitionType) && (
138
            <MiniRanking
139
              teamId={general.homeTeamId || general.awayTeamId || 0}
140
              homeTeam={general.homeClub?.name}
141
              awayTeam={general.awayClub?.name}
142
            />
143
          )}
144
        </section>
145
      </Layout>
146
    )
147
  } else {
148
    return (
149
      <Layout>
150
        <Spinner />
151
      </Layout>
152
    )
153
  }
154
}
155
156
const renderScore = (resultHome?: number, resultAway?: number) => {
157
  return resultHome !== null && resultAway !== null ? (
158
    <div className={`game__details__vs game__details__vs--score`}>
159
      {renderScoreWithWinnerIndicator(resultHome || 0, resultAway || 0, `home`)}
160
      <span className={`match-details__divider`}>&nbsp;-&nbsp;</span>
161
      {renderScoreWithWinnerIndicator(resultAway || 0, resultHome || 0, `away`)}
162
    </div>
163
  ) : (
164
    <div className={`game__details__vs`}>VS</div>
165
  )
166
}
167
168
const renderScoreWithWinnerIndicator = (result1: number, result2: number, extraClass?: string) => {
169
  return result1 > result2 ? (
170
    <span className={`game__details__winner game__details__winner--${extraClass}`}>{result1}</span>
171
  ) : (
172
    <span className={`game__details__loser`}>{result1}</span>
173
  )
174
}
175
176
const renderLineup = (lineup: MatchDetailsLineupItem[], substitutes: MatchDetailsSubstituteItem[]) => {
177
  return (
178
    <Fragment>
179
      {renderLineupHeader()}
180
      {lineup.map((element, i) => renderLineupLine(i, element))}
181
      <hr />
182
      {substitutes.map((element, i) => renderSubLine(i, element))}
183
    </Fragment>
184
  )
185
}
186
187
const renderLineupHeader = () => {
188
  return (
189
    <div className={`lineup__header`}>
190
      <span className={`lineup__header__item lineup__item--status`}></span>
191
      <span className={`lineup__header__item lineup__item--number`}>#</span>
192
      <span className={`lineup__header__item lineup__item--name`}>Name</span>
193
      <span className={`lineup__header__item lineup__item--time`}>
194
        <Icon icon="fa-clock-o" />
195
      </span>
196
    </div>
197
  )
198
}
199
200
const renderLineupLine = (i: React.Key, element: MatchDetailsLineupItem) => {
201
  return (
202
    <div className={`lineup__row lineup__row--lineup`} key={i}>
203
      <span
204
        className={`lineup__row__item lineup__item--status`}
205
        style={{
206
          backgroundImage: `url(${element.changed ? iconSubOut : iconStart})`,
207
        }}
208
        title={`${element.changed ? `Basisspeler gewisseld` : `Basisspeler`}`}
209
      ></span>
210
      <span className={`lineup__row__item lineup__item--number`}>{element.number}</span>
211
      <span className={`lineup__row__item lineup__item--name`}>
212
        {element.playerName} {element.captain && `(C)`}
213
      </span>
214
      <span className={`lineup__row__item lineup__item--time`}>{element.minutesPlayed}'</span>
215
    </div>
216
  )
217
}
218
219
const renderSubLine = (i: React.Key, element: MatchDetailsSubstituteItem) => {
220
  return (
221
    <div className={`lineup__row lineup__row--substitute`} key={i}>
222
      <span
223
        className={`lineup__row__item lineup__item--status`}
224
        style={{
225
          backgroundImage: `url(${element.changed ? iconSubIn : iconBench})`,
226
        }}
227
        title={`${element.changed ? `Wisselspeler ingevallen` : `Wisselspeler`}`}
228
      ></span>
229
      <span className={`lineup__row__item lineup__item--number`}>{element.number}</span>
230
      <span className={`lineup__row__item lineup__item--name`}>{element.playerName}</span>
231
      <span className={`lineup__row__item lineup__item--time`}>{element.minutesPlayed}'</span>
232
    </div>
233
  )
234
}
235
236
const renderEvents = (events: MatchDetailsEventItem[], homeTeamId: number) => {
237
  return <Fragment>{events.map((element, i) => renderEventLine(i, element, homeTeamId))}</Fragment>
238
}
239
240
const renderEventLine = (i: React.Key, element: MatchDetailsEventItem, homeTeamId: number) => {
241
  const homeTeam = element.clubId == homeTeamId
242
  let actionIcon = null
243
  let actionMessage = ``
244
  let actionText = ``
245
246
  // Backwards compatibility:
247
  if (typeof element.action === `string`) {
248
    switch (element.action) {
249
      case `geel`:
250
        actionIcon = iconCardYellow
251
        actionText = `Gele kaart voor`
252
        actionMessage = `Gele kaart`
253
        break
254
      case `rood`:
255
        actionIcon = iconCardRed
256
        actionText = `Rode kaart voor`
257
        actionMessage = `Rode kaart`
258
        break
259
      case `tweedegeel`:
260
        actionIcon = iconCardYellowRed
261
        actionText = `Tweede gele kaart voor`
262
        actionMessage = `Tweede gele kaart`
263
        break
264
      case `doelpunt`:
265
        actionIcon = iconGoal
266
        actionText = `${element?.goalsHome} - ${element?.goalsAway} — Doelpunt gescoord door`
267
        actionMessage = `Doelpunt`
268
        break
269
      case `minuteOut`:
270
        actionIcon = iconSubOut
271
        actionText = `Speler uit:`
272
        actionMessage = `Wissel`
273
        break
274
      case `minuteIn`:
275
        actionIcon = iconSubIn
276
        actionText = `Speler in:`
277
        actionMessage = `Wissel`
278
        break
279
    }
280
  } else {
281
    switch (element.action.type) {
282
      case `GOAL`:
283
        actionIcon = iconGoal
284
        actionText = `${element?.goalsHome} - ${element?.goalsAway} — Doelpunt gescoord door`
285
        actionMessage = `Doelpunt`
286
        break
287
      case `CARD`:
288
        switch (element.action.subtype) {
289
          case `YELLOW`:
290
            actionIcon = iconCardYellow
291
            actionText = `Gele kaart voor`
292
            actionMessage = `Gele kaart`
293
            break
294
          case `RED`:
295
            actionIcon = iconCardRed
296
            actionText = `Rode kaart voor`
297
            actionMessage = `Rode kaart`
298
            break
299
          case `DOUBLE_YELLOW`:
300
            actionIcon = iconCardYellowRed
301
            actionText = `Tweede gele kaart voor`
302
            actionMessage = `Tweede gele kaart`
303
            break
304
        }
305
    }
306
  }
307
308
  return (
309
    <div className={`event__row ${homeTeam ? `event__row--home` : `event__row--away`}`} key={i}>
310
      {homeTeam && (
311
        <span className={`event__row__item event__row__item--home lineup__item--name`}>
312
          {actionText} {element.playerName}
313
        </span>
314
      )}
315
      {homeTeam && (
316
        <span
317
          className={`event__row__item event__row__item--home lineup__item--action center`}
318
          style={{ backgroundImage: `url(${actionIcon})` }}
319
          title={actionMessage}
320
        ></span>
321
      )}
322
      <span className={`event__row__item lineup__item--time center`}>{element.minute}'</span>
323
      {homeTeam || (
324
        <span
325
          className={`event__row__item event__row__item--away lineup__item--action center`}
326
          style={{ backgroundImage: `url(${actionIcon})` }}
327
          title={actionMessage}
328
        ></span>
329
      )}
330
      {homeTeam || (
331
        <span className={`event__row__item event__row__item--away lineup__item--name`}>
332
          {actionText} {element.playerName}
333
        </span>
334
      )}
335
    </div>
336
  )
337
}
338
339
export default GamePage
340